package com.terra.ns.imp.common.satoken.utils

import cn.dev33.satoken.exception.NotLoginException
import cn.dev33.satoken.exception.NotLoginException.INVALID_TOKEN
import cn.dev33.satoken.stp.SaLoginModel
import cn.dev33.satoken.stp.StpUtil
import com.terra.ns.imp.common.redis.utils.RedisUtils
import com.terra.ns.imp.common.satoken.constant.LoginDeviceType
import com.terra.ns.imp.system.api.entity.LoginUser
import java.time.Duration

/**
@author qins
@date 2023/6/1
@desc使用SaToken管理登录及会员信息
 */
object LoginUtils {

    private const val USER_LOGIN_INFO_KEY = "loginUser"

    private const val USER_PERM_KEY = "loginUserPerm"

    private const val USER_ROLE_KEY = "loginUserRole"

    private const val USER_DEPARTMENT_KEY = "loginUserDepartment"

    /**
     * 登录
     * @param loginUser 基础用户信息
     * @param loginDevice 设定登录设备
     * @return 返回token
     */
    fun login(loginUser: LoginUser, loginDevice: LoginDeviceType = LoginDeviceType.WEB) : String {
        val loginModel = SaLoginModel()
        loginModel.setDevice(loginDevice.device)
        StpUtil.login(loginUser.code, loginModel)
        setLoginUser(loginUser)
        return StpUtil.getTokenValue()
    }


    /**
     * 退出登录
     */
    fun logout() {
        if(StpUtil.isLogin()) {
            StpUtil.logout()
        }
    }


    /**
     * 设置登录会话租户信息
     */
    private fun setLoginUser(loginUser: LoginUser) {
        StpUtil.getTokenSession().set(USER_LOGIN_INFO_KEY, loginUser)
    }

    /**
     * 设置登录会话权限信息
     */
    fun setPerms(permList: List<String>) {
        StpUtil.getTokenSession().set(USER_PERM_KEY, permList)
    }
    /**
     * 设置登录会话角色信息
     */
    fun setRoles(roleList: List<String>) {
        StpUtil.getTokenSession().set(USER_ROLE_KEY, roleList)
    }

    fun setDepts(deptList:List<String>){
        StpUtil.getTokenSession().set(USER_DEPARTMENT_KEY,deptList)
    }

    private fun getLoginUser() : LoginUser {
        val loginUser = StpUtil.getTokenSession().get(USER_LOGIN_INFO_KEY)
            ?: throw NotLoginException("未设置登录者用户信息", StpUtil.getLoginType(), INVALID_TOKEN)
        return loginUser as LoginUser
    }

    fun getUserName() : String {
        return getLoginUser().name
    }

    fun getPerms() : List<String> {
        return StpUtil.getTokenSession().get(USER_PERM_KEY) as List<String>
    }

    fun getRoles() : List<String> {
        return StpUtil.getTokenSession().get(USER_ROLE_KEY) as List<String>
    }

    fun getUserCode() : String {
        return getLoginUser().code
    }

    fun getDepts():List<String>{
        return StpUtil.getTokenSession().get(USER_DEPARTMENT_KEY) as List<String>
    }


    /**
     * 获取并自增密码错误次数值
     */
    fun getPasswordErrorCount(phone: String): Long {
        return RedisUtils.getAndSetAtomicValue(getPwdErrorCountKey(phone), 1,  180)
    }

    /**
     * 锁定用户
     * @param phone 用户唯一手机号
     * @param  lockTime 锁定时长
     */
    fun lockLoginUser(phone: String, lockTime: Long) {
        RedisUtils.set(getLockUserKey(phone), true, Duration.ofSeconds(lockTime))
    }

    /**
     * 密码错误次数验证key
     */
    fun getPwdErrorCountKey(phone: String) = "password:errorCount:$phone"

    /**
     * 用户锁定key
     */
    fun getLockUserKey(phone: String) = "locked:user:$phone"
}